#include <BALL/KERNEL/system.h>
#include <BALL/FORMAT/PDBFile.h>

struct PDBException : public std::exception
{
    const char* msg;
    PDBException(const char* msg) : msg(msg) {}
    const char* what() const throw()
    {
        return msg;
    }
};

class Dyn2PDB
{
    std::vector<float> i_dont_know_what_this_is;

public:

    void read_xyz(const char* fname)
    {
        // TODO
        // use either stringstreams, or mili::from_string
        // since these perform validations
        const float CONVERSION_FACTOR = 3.4;
        int natoms;
        char e;
        float pos[3];
        std::ifstream f(fname);
        std::string line;
        getline(f, line);
        natoms = atoi(line.c_str());
        getline(f, line); // skip comments
        for (int i = 0; i < natoms; i++)
        {
            getline(f, line);
            sscanf(line.c_str(), "%c %f %f %f", &e, pos, pos + 1, pos + 2);
            for (int j = 0; j < 3; j++)
            {
                pos[j] /= CONVERSION_FACTOR;
            }
            i_dont_know_what_this_is.insert(i_dont_know_what_this_is.end(), pos, pos + 3);
            // std::cerr << i << ":"<<pos[0]<< " "<<pos[1]<< " "<<pos[2]<< std::endl;
        }
    }

    void update_pdb(const char* src, const char* dest)
    {
        BALL::System system;

        // Read the reference model
        {
            BALL::PDBFile file(src);
            if (file.bad())
            {
                throw PDBException("Couldn't read PDB.");
            }

            file >> system;
            file.close();
        }

        // Overwrite positions
        std::vector<float>::const_iterator it0 = i_dont_know_what_this_is.begin();
        for (BALL::AtomIterator it1 = system.beginAtom(); +it1; ++it1)
        {
            it1->getPosition().x = *it0++;
            it1->getPosition().y = *it0++;
            it1->getPosition().z = *it0++;
        }

        // Write the results
        {
            BALL::PDBFile file(dest, std::ios::out);

            if (file.bad())
            {
                throw PDBException("Couldn't write PDB.");
            }
            file << system;
            file.close();
        }

    }
};

